⚡ 30 秒速记

  • 先定位昂贵组件和交互,不追求零渲染
  • 状态尽量靠近使用处,避免无关范围更新
  • memo 控属性更新边界,缓存必须有稳定依赖
  • 大列表减少实际渲染节点
  • 自定义比较成本与正确性都要验证

React 性能优化先找哪次更新让用户等,再减少那次更新里不必要的工作。 状态放得过高会扩大影响范围,长列表可能需要虚拟化,昂贵计算才值得缓存。memo 能帮助跳过属性未变的重复渲染,但自身状态和上下文仍会更新;引用每次都新建时,缓存也难以命中。改完用真实交互复测,避免比较函数比重新渲染还贵。

版本校准: 本文若分析 ReactDOM.render、旧生命周期或栈调和,应把它视为理解架构演进的历史路径。React 19 已移除 ReactDOM.render,当前客户端入口使用 createRoot;并发渲染也必须区分可中断的渲染阶段与同步提交阶段。迁移前对照 React 19 官方升级指南。

  • 使用 shouldComponentUpdate 规避冗余的更新逻辑
  • PureComponent + Immutable.js
  • React.memo 与 useMemo

注:这 3 个思路同时也是 React 面试中“性能优化”这一环的核心所在

# 善用 shouldComponentUpdate

shouldComponentUpdate 的调用形式如下:

shouldComponentUpdate(nextProps, nextState)
  • render 方法由于伴随着对虚拟 DOM 的构建和对比,过程可以说相当耗时。而在 React 当中,很多时候我们会不经意间就频繁地调用了 render。为了避免不必要的 render 操作带来的性能开销,React 提供了 shouldComponentUpdate 这个口子。React 组件会根据 shouldComponentUpdate 的返回值,来决定是否执行该方法之后的生命周期,进而决定是否对组件进行 re-render(重渲染)。
  • shouldComponentUpdate 的默认值为 true,也就是说 “无条件 re-render”。在实际的开发中,我们往往通过手动往 shouldComponentUpdate 中填充判定逻辑,来实现“有条件的 re-render”。

首先我们来看两个子组件的代码,这里为了尽量简化与数据变更无关的逻辑,ChildA 和 ChildB 都只负责从父组件处读取数据并渲染,它们的编码分别如下所示。

// ChildA.js:

import React from "react";
export default class ChildA extends React.Component {
  render() {
    console.log("ChildA 的render方法执行了");
    return (
      <div className="childA">
        子组件A的内容:
        {this.props.text}
      </div>
    );
  }
}
webapp
公众号
开发者导航
切换夜间模式
点击侧边栏上一篇
点击侧边栏下一篇
折叠侧边栏
收起全部